#!/bin/bash

default_header_ext="h hh hpp"
default_source_ext="c cc cpp"

usage() {
    echo "Usage:" $(basename $0) "[-fhsHS --help] [path]"
    echo "  Produce a list of 'source' files from current dir, or path if given."
    echo "  By default lists both headers and sources and these extentions are used:"
    echo "  headers: '$default_header_ext'"
    echo "  sources:  '$default_source_ext'"
    echo "  -h list header files."
    echo "  -s list source files."
    echo "  -f Use the 'file' command to classify as a source, then if there is an"
    echo "     h in the extension it is a header else source. This will match a lot"
    echo "     of potential files, e.g. html with C source code in it."
    echo " -H quoted list of header extensions."
    echo "    (adds -h, unless -s given.)"
    echo " -S quotedlist of source extensions"
    echo "    (adds -s, unless -h given.)"
    echo " -i quoted list of directories relative to 'path' to include"
    echo " -x quoted list of directories to exclude"
    echo " Note: If both -i and -x are defined -x wins. But using both is"
    echo "       still useful when a sub directory of an included directory"
    echo "       should be excluded."
}

opts=$(getopt -o "fhsH:S:i:x:" --long "help" -n $(basename $0) -- "$@")
if [ $? -ne 0 ]; then
	usage
	exit 1
fi

eval set -- "$opts"

while true; do
    case "$1" in
	-f) use_file_cmd=true ;;
	-h) list_headers=true ;;
	-s) list_sources=true ;;
	-H) header_ext="$2"
	    shift
	    ;;
	-S) source_ext="$2"
	    shift
	    ;;
    -i) inclusion_list="$2"
        shift
        ;;
    -x) exclusion_list="$2"
        shift
        ;;
	--help)
	    usage
	    exit 1
	    ;;
	'--')
	    shift
	    break
    esac
    shift
done
shift $((OPTIND-1))

path="./"
if [[ -n $1 ]]; then
    path=$1
fi

if ! [[ $list_headers || $list_sources ]]; then
    list_headers=true
    list_sources=true
fi

if [[ -z $header_ext ]]; then
    header_ext=$default_header_ext
fi

if [[ -z $source_ext ]]; then
    source_ext=$default_source_ext
fi

# regex when using file cmd
if [[ $list_headers && $list_sources ]]; then
    regex='.*'
elif [[ $list_headers ]]; then
    regex='h[^.]*$'  # h in extension
else
    regex='[.][^h]*$'  # no h in extension
fi

# build find command
if ! [[ -z $exclusion_list ]]; then
    for exclude in $exclusion_list
    do
        if [[ -z $exclusion_cmd ]]; then
            exclusion_cmd="-type d \("
        else
            exclusion_cmd="$exclusion_cmd -o"
        fi

        exclusion_cmd="$exclusion_cmd -name '$exclude'"
    done
    exclusion_cmd="$exclusion_cmd \) -prune -o "
fi

if ! [[ -z $inclusion_list ]]; then
    for inc in $inclusion_list
    do
        full=$path/$inc
        inclusion_list_extended="$full $inclusion_list_extended"
    done
    unset path
fi

FIND="find $path $inclusion_list_extended $exclusion_cmd -type f -print"

for file in $(eval $FIND)
do
    if [[ $use_file_cmd ]]; then
	if [[ `file -b $file` =~ "source" ]]; then
            if [[ $file =~ $regex ]]; then
		echo $(readlink -m $file)
            fi
	fi
    else
	regex="\b${file##*.}\b"
	if [[ $list_headers && $header_ext =~ $regex ]]; then
	    echo $(readlink -m $file)
	fi

	if [[ $list_sources && $source_ext =~ $regex ]]; then
       	    echo $(readlink -m $file)
	fi

    fi

done
